#include <iostream>
#include "scope.h"

// ia ia codethulhu fhtagn
template <class keytype, class T>
scope<keytype, T> * scope<keytype, T>::get_path(std::vector<keytype> path)
{
   scope<keytype, T> * current = this;
   for ( int i = 0; i < path.size(); i ++ )
   {
      current = current->get_scope(path[i]);
      if ( !current ) { return NULL; }
   }
   return current;
}

template <class keytype, class T>
T scope<keytype, T>::get_var(keytype n)
{
   if ( variables[n] ) { return variables[n]; }
   else if ( superscope != this ) { return superscope->get_var(n); }
   else { return NULL; }
}


template <class keytype, class T>
T scope<keytype, T>::get_path_var(std::vector<keytype> path, keytype n)
{
   return get_path(path)->get_var(n);
}

template <class keytype, class T>
scope<keytype, T> * scope<keytype, T>::get_scope(keytype n)
{
   for ( unsigned int i = 0; i < subscopes.size(); i ++ )
   {
      if ( subscopes[i]->name == n ) { return subscopes[i]; }
   }
   return NULL;
}

template <class keytype, class T>
scope<keytype, T> * scope<keytype, T>::get_path_scope(std::vector<keytype> path, keytype n)
{
   return get_path(path)->get_scope(n);
}

template <class keytype, class T>
void scope<keytype, T>::add_var(keytype n, T value)
{
   variables[n] = value;
}

template <class keytype, class T>
void scope<keytype, T>::add_path_var(std::vector<keytype> path, keytype n, T value)
{
   get_path(path)->add_var(n, value);
}

template <class keytype, class T>
scope<keytype, T> * scope<keytype, T>::add_scope(keytype n)
{
   scope<keytype, T> * temp = new scope<keytype, T>;
   temp->superscope = this;
   temp->name = n;
   temp->global = global;
   subscopes.push_back(temp);
   return temp;
}

template <class keytype, class T>
scope<keytype, T> * scope<keytype, T>::add_path_scope(std::vector<keytype> path, keytype n)
{
   return get_path(path)->add_scope(n);
}

template <class keytype, class T>
bool scope<keytype, T>::is_superscope(scope<keytype, T> * input)
{
   if ( superscope == input ) { return 1; }
   else if ( superscope == NULL ) { return 0; }
   else { return superscope->is_superscope(input); }
}

template <class keytype, class T>
bool scope<keytype, T>::is_subscope(scope<keytype, T> * input)
{
   return input->is_superscope(this);
}

template <class keytype, class T>
void scope<keytype, T>::detach()
{
   unsigned int i = 0;
   while ( superscope->subscopes[i]->name != name ) { i ++; }
   superscope->subscopes.erase(superscope->subscopes.begin()+i);
   superscope = global;
   global->subscopes.push_back(this);
}

template <class keytype, class T>
scope<keytype, T> * scope<keytype, T>::attach(scope<keytype, T> * input)
{
   unsigned int i = 0;
   while ( superscope->subscopes[i]->name != name ) { i ++; }
   superscope->subscopes.erase(superscope->subscopes.begin()+i);
   superscope = input;
   input->subscopes.push_back(this);
   return this;
}

template <class keytype, class T>
scope<keytype, T> * scope<keytype, T>::attach_sub(scope<keytype, T> * input)
{
   return input->attach(this);
}
